package org.apache.rocketmq.client.java.impl.producer;

import org.apache.rocketmq.client.java.clientapis.ClientConfiguration;
import org.apache.rocketmq.client.java.clientapis.producer.Producer;
import org.apache.rocketmq.client.java.clientapis.producer.ProducerBuilder;
import org.apache.rocketmq.client.java.clientapis.producer.TransactionChecker;
import org.apache.rocketmq.client.java.message.MessageBuilderImpl;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
 * @author：陈清风扬，个人微信号：chenqingfengyangjj。
 * @date:2025/6/10
 * @方法描述：生产者客户端构建器
 */
public class ProducerBuilderImpl implements ProducerBuilder {

    //封装生产者客户端配置信息的成员变量
    private ClientConfiguration clientConfiguration = null;

    //存储生产者要发送消息的主题集合
    private final Set<String> topics = new HashSet<>();

    //发送消息的最大失败重试次数
    private int maxAttempts = 3;

    //事务消息的检查器，这个检查器在第九版本代码中还不会用到，所以我并没有真的引入
    private TransactionChecker checker = null;

    //构造方法
    public ProducerBuilderImpl() {
    }

    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @方法描述：设置客户端配置信息的方法
     */
    @Override
    public ProducerBuilder setClientConfiguration(ClientConfiguration clientConfiguration) {
        this.clientConfiguration = checkNotNull(clientConfiguration, "clientConfiguration should not be null");
        return this;
    }


    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @方法描述：设置要发送消息的Topic主题的方法
     */
    @Override
    public ProducerBuilder setTopics(String... topics) {
        final Set<String> set = Arrays.stream(topics).peek(topic -> checkNotNull(topic, "topic should not be null"))
                .peek(topic -> checkArgument(MessageBuilderImpl.TOPIC_PATTERN.matcher(topic).matches(), "topic does not "
                        + "match the regex [regex=%s]", MessageBuilderImpl.TOPIC_PATTERN.pattern()))
                .collect(Collectors.toSet());
        this.topics.addAll(set);
        return this;
    }


    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @方法描述：设置发送消息的最大失败重试次数的方法
     */
    @Override
    public ProducerBuilder setMaxAttempts(int maxAttempts) {
        checkArgument(maxAttempts > 0, "maxAttempts should be positive");
        this.maxAttempts = maxAttempts;
        return this;
    }

    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @方法描述：设置事务消息检查器的方法
     */
    @Override
    public ProducerBuilder setTransactionChecker(TransactionChecker checker) {
        this.checker = checkNotNull(checker, "checker should not set null");
        return this;
    }


    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @方法描述：构建生产者客户端对象的方法
     */
    @Override
    public Producer build() {
        checkNotNull(clientConfiguration, "clientConfiguration has not been set yet");
        //在这里创建了生产者客户端对象
        final ProducerImpl producer = new ProducerImpl(clientConfiguration, topics, maxAttempts, checker);
        //在这里启动了生产者客户端对象，异步起动，并且等待客户端启动完成
        producer.startAsync().awaitRunning();
        return producer;
    }
}
